package org.newlucene.core.search;

import java.io.IOException;

import org.newlucene.core.index.*;

public class SloppyPhraseSearcher extends PhraseSearcher
{
	Term[] terms;
	private int slop;

    public SloppyPhraseSearcher(IndexReader indexReader, Term[] terms, int slop) throws IOException
    {
    	super(indexReader, terms);
    	this.terms = terms;
    	this.slop = slop;
    }

    protected final float phraseFreq() throws IOException
    {
    	pq.clear();
    	int end = 0;
        for (PhrasePositions pp = first; pp != null; pp = pp.next)
        {
            pp.firstPosition();
            if (pp.position > end)
            {
            	end = pp.position;
            }
            pq.put(pp); // build pq from list
        }

        float freq = 0.0f;
		boolean done = false;
		do {
			PhrasePositions pp = (PhrasePositions) pq.pop();
			int start = pp.position;
			int next = ((PhrasePositions) pq.top()).position;
			for (int pos = start; pos <= next; pos = pp.position) 
			{
				start = pos; // advance pp to min window
				if (!pp.nextPosition()) 
				{
					done = true; // ran out of a term -- done
					break;
				}
			}

			int matchLength = end - start;
			if (matchLength <= slop)
			{
				freq += 1.0 / (matchLength + 1); // penalize longer matches
			}
			if (pp.position > end)
			{
				end = pp.position;
			}
			pq.put(pp); // restore pq
		} 
		while (!done);

		return freq;
	}
    
    public String explain()
    {
    	// build the keyword string
    	StringBuilder sb = new StringBuilder();
    	// field name
    	sb.append(terms[0].field()).append(":");
    	// field value
    	sb.append("\"");
    	for (Term term : terms)
    	{
    		sb.append(term.text()).append(" ");
    	}
    	sb.deleteCharAt(sb.length() - 1); // delete last white space
    	sb.append("\"");
    	// slop
    	if (slop != 0)
    	{
    		sb.append("~").append(slop);
    	}
    	// boost
    	if (boost != 1.0f)
    	{
    		sb.append("^").append(boost);
    	}
    	return sb.toString();
    }
}